/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦，本文采用木兰宽松许可证第2版]
 * 
 * https://zhiqim.org/project/zhiqim_components/zhiqim_upload_large.htm
 *
 * Zhiqim UploadLarge is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.uploadlarge;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import org.zhiqim.httpd.HttpExecutor;
import org.zhiqim.httpd.HttpRequest;
import org.zhiqim.httpd.HttpResponse;
import org.zhiqim.httpd.constants.HttpMimeType;
import org.zhiqim.kernel.util.DateTimes;
import org.zhiqim.kernel.util.Files;
import org.zhiqim.kernel.util.Streams;
import org.zhiqim.kernel.util.Strings;
import org.zhiqim.kernel.util.Urls;
import org.zhiqim.kernel.util.Validates;
import org.zhiqim.uploadlarge.dbo.UpllFile;

/**
 * 上传文件访问服务，用于固定访问地址为/service/upll/*，中间*=${fileId}，实际处理在forward中
 *
 * @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
 */
public class ZulAccess implements HttpExecutor, ZulConstants
{
    @Override
    public boolean isMatch(String pathInContext)
    {
        return Validates.isMatch(pathInContext, _PATH_SERVICE_UPLOAD_LARGE_ACCESS_);
    }
    
    @Override
    public void handle(HttpRequest request, HttpResponse response) throws IOException
    {
        String access = request.getContextAttribute(ZulBootstrap.class).getAccessUrl();
        if (Validates.isNotEmpty(access))
        {//跳转优先，成功则跳转到对应的连接
            try{request.forwardTo(access);}
            catch(Exception e){response.sendHeader(_500_INTERNAL_SERVER_ERROR_);}
            return;
        }

        /**************************************************************/
        //当前处理方式
        /**************************************************************/
        String fileName = Strings.lastIndexOfString(request.getPathInContext(), "/");
        String fileExt = Files.getFileExt(fileName);
        String fileId = Strings.removeEndsWith(fileName, "."+fileExt);
        
        UpllFile upload = null;
        try{upload = ZulUploader.getFile(fileId);}
        catch (Exception e){response.sendHeader(_500_INTERNAL_SERVER_ERROR_);return;}
        if (upload == null)
        {//未找到该编号
            response.sendError(_404_NOT_FOUND_);
            return;
        }
        
        String filePath = Zuls.getFilePath(request, upload);
        if (Validates.isNotEmpty(fileExt))
        {//检查文件格式是否一致
            String ext = Files.getFileExt(filePath);
            if (!fileExt.equals(ext))
            {//地址格式不正确
                response.sendError(_404_NOT_FOUND_);
                return;
            }
        }
        
        File file = new File(filePath);
        if (!file.exists() || !file.isFile())
        {//不存在或不是文件
            response.sendError(_404_NOT_FOUND_);
            return;
        }
        
        if (file.isHidden() || !file.canRead())
        {//隐藏、不可读和文件大小超限
            response.sendError(_403_FORBIDDEN_);
            return;
        }
        
        //文件类型
        String contentType = upload.getContentType();
        if (Validates.isEmptyBlank(contentType) || _APPLICATION_OCTET_STREAM_.equals(contentType))
        {//对于未配置类型或二进制类型，再到MIME表中再查一次
            contentType = HttpMimeType.getResourceMimeType(fileExt);
        }
        response.setContentType(contentType);
        
        if (!Validates.isContain("html,js,css,png,jpg,gif", ",", fileExt))
        {//上传的页面和图片暂时允许浏览器执行
            
            String downName = Urls.encodeUTF8(upload.getFileName());
            
            String userAgent = request.getUserAgent();
            if(Validates.isNotEmpty(userAgent) && userAgent.contains("aria2"))  //aria2方式下载，则不编码，适应客户端下载
                downName = upload.getFileName();
            
            if (request.isChrome())
            {//chrome不支持括号也是醉了
                downName = downName.replaceAll("%28", "(");
                downName = downName.replaceAll("%29", ")");
            }
            
            if (request.isFirefox())
                response.setHeader(_CONTENT_DISPOSITION_, "attachment; filename*=UTF-8''"+upload.getFileName());
            else
                response.setHeader(_CONTENT_DISPOSITION_, "attachment; filename="+downName);
        }
        
        //缓存控制字段
        if (Validates.isNotEmpty(upload.getCacheControl()))
            response.setCacheControl(upload.getCacheControl());
        
        long lastModified = file.lastModified();
        String lastModifiedTime = DateTimes.getDateTimeHttp(lastModified);
        String ifModifiedSince = request.getHeader(_IF_MODIFIED_SINCE_);
        if (ifModifiedSince != null && ifModifiedSince.indexOf(lastModifiedTime) != -1)
        {//时间相等
            response.sendHeader(_304_NOT_MODIFIED_);
            return;
        }
        
        response.setHeader(_ACCEPT_RANGES_, _BYTES_);
        response.setHeader(_LAST_MODIFIED_, lastModifiedTime);
        response.setHeader(_CONTENT_LENGTH_, file.length());
        if (request.isMethodResponseContent())
        {//GET,POST
            FileInputStream fis = new FileInputStream(file);
            Streams.putBytes(fis, response.getOutputStream());
        }
        
        response.commit();
    }
}
